package com.test.shadow;

import android.Manifest;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.PermissionChecker;

import com.tencent.shadow.dynamic.host.EnterCallback;
//import com.tencent.shadow.core.manager.*;
import com.test.constants.Constant;
import com.test.shadow.manager.PluginHelper;
// import com.test.shadow.manager.FastPluginManager;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.ExecutionException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

import static com.tencent.shadow.core.utils.Md5.md5File;

import org.apache.commons.io.FileUtils;
import org.json.JSONException;


public class MainActivity extends AppCompatActivity {

    private ProgressBar progressBar;
    private Handler mHandler = new Handler();
    private Button btn1;
    private Button btn2;
    private Button btn3;
    private Button btn4;
    private TextView textView;
    private ServiceConnection sc;
    private LoadingDialog loadingDialog;
//    private BasePluginManager bpm;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        loadingDialog = new LoadingDialog(this);
        progressBar = (ProgressBar) findViewById(R.id.pb);
        textView = (TextView) findViewById(R.id.textView);
        btn1 = (Button) findViewById(R.id.btn1);
        btn2 = (Button) findViewById(R.id.btn2);
        btn3 = (Button) findViewById(R.id.btn3);
        btn4 = (Button) findViewById(R.id.btn4);
        btn4.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                downloadZIP();
            }
        });
    }


    // 打开其中一个插件
    public void start_plugin(View view) {
        PluginHelper.getInstance().singlePool.execute(new Runnable() {
            @Override
            public void run() {
                MyApplication.getApp().loadPluginManager(PluginHelper.getInstance().pluginManagerFile);

                /**
                    * @param context context
                    * @param formId  标识本次请求的来源位置，用于区分入口
                    * @param bundle  参数列表, 建议在参数列表加入自己的验证
                    * @param callback 用于从PluginManager实现中返回View
                    */
                Bundle bundle = new Bundle();//插件 zip，这几个参数也都可以不传，直接在 PluginManager 中硬编码
                bundle.putString(Constant.KEY_PLUGIN_ZIP_PATH, PluginHelper.getInstance().pluginZipFile.getAbsolutePath());
                bundle.putString(Constant.KEY_PLUGIN_NAME, Constant.PLUGIN_APP_NAME);// partKey 每个插件都有自己的 partKey 用来区分多个插件，如何配置在下面讲到
                bundle.putString(Constant.KEY_ACTIVITY_CLASSNAME, "com.test.plugin_app.SplashActivity");//要启动的插件的Activity页面
                bundle.putBundle(Constant.KEY_EXTRAS, new Bundle()); // 要传入到插件里的参数
                MyApplication.getApp().getPluginManager().enter(MainActivity.this, Constant.FROM_ID_START_ACTIVITY, bundle, new EnterCallback() {
                    @Override
                    public void onShowLoadingView(View view) {
                        loading("VISIBLE");
                        Log.e("PluginLoad", "onShowLoadingView");
                    }

                    @Override
                    public void onCloseLoadingView() {
                        loading("INVISIBLE");
                        Log.e("PluginLoad", "onCloseLoadingView");
                    }

                    @Override
                    public void onEnterComplete() {
                        // 启动成功
                        Log.e("PluginLoad", "onEnterComplete");
                    }
                });
            }
        });
    }

    // 打开其中一个插件
    public void start_plugin_other(View view) {
        PluginHelper.getInstance().singlePool.execute(new Runnable() {
            @Override
            public void run() {
                MyApplication.getApp().loadPluginManager(PluginHelper.getInstance().pluginManagerFile);

                /**
                 * @param context context
                 * @param formId  标识本次请求的来源位置，用于区分入口
                 * @param bundle  参数列表, 建议在参数列表加入自己的验证
                 * @param callback 用于从PluginManager实现中返回View
                 */
                Bundle bundle = new Bundle();//插件 zip，这几个参数也都可以不传，直接在 PluginManager 中硬编码
                bundle.putString(Constant.KEY_PLUGIN_ZIP_PATH, PluginHelper.getInstance().pluginZipFile.getAbsolutePath());
                bundle.putString(Constant.KEY_PLUGIN_NAME, Constant.PLUGIN_OTHER_NAME);// partKey 每个插件都有自己的 partKey 用来区分多个插件，如何配置在下面讲到
                bundle.putString(Constant.KEY_ACTIVITY_CLASSNAME, "com.test.plugin_other.MainActivity");//要启动的插件的Activity页面
                bundle.putBundle(Constant.KEY_EXTRAS, new Bundle()); // 要传入到插件里的参数
                MyApplication.getApp().getPluginManager().enter(MainActivity.this, Constant.FROM_ID_START_ACTIVITY, bundle, new EnterCallback() {
                    @Override
                    public void onShowLoadingView(View view) {
                        loading("VISIBLE");
                        Log.e("PluginLoad", "onShowLoadingView");
                    }

                    @Override
                    public void onCloseLoadingView() {
                        loading("INVISIBLE");
                        Log.e("PluginLoad", "onCloseLoadingView");
                    }

                    @Override
                    public void onEnterComplete() {
                        // 启动成功
                        Log.e("PluginLoad", "onEnterComplete");
                    }
                });
            }
        });
    }

    /**
     * 下载zip文件
     */
    private void downloadZIP() {
        String[] permission = {
            Manifest.permission.WRITE_EXTERNAL_STORAGE,
            Manifest.permission.READ_EXTERNAL_STORAGE
        };
        if (Build.VERSION.SDK_INT >= 23) {
            if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
                    != PermissionChecker.PERMISSION_GRANTED
                    && ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.READ_EXTERNAL_STORAGE)
                    != PermissionChecker.PERMISSION_GRANTED
            ) {
                ActivityCompat.requestPermissions(MainActivity.this, permission, 101);
            } else {
                startDownload();
            }
        } else {
            startDownload();
        }
    }

    private void startDownload() {
        // try {
        //     PluginHelper.getInstance().downFile();
        // } catch (IOException e) {
        //     e.printStackTrace();
        // }
        loadingDialog.show();
        btn3.setEnabled(false);
        btn4.setEnabled(false);
        sc = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
                DownloadZipService.Binder binder = (DownloadZipService.Binder) iBinder;
                binder.getService().setUpdateProgressListner(new CallBackListener() {
                    @Override
                    public void CallBack(int code, Object object) {
                        Message msg = new Message();
                        msg.what = 1;
                        handler.sendMessage(msg);
                    }
                });
            }

            @Override
            public void onServiceDisconnected(ComponentName componentName) {

            }
        };

        Intent intent = new Intent(MainActivity.this, DownloadZipService.class);
        intent.putExtra("zipurl", "https://kunyu.test.abontest.com/plugin-app-copy-debug.zip");
        if (sc != null) {
            MainActivity.this.bindService(intent, sc, Context.BIND_AUTO_CREATE);
        }
    }


    // 打开其中一个插件
    public void copy(View view) {
        PluginHelper.getInstance().singlePool.execute(new Runnable() {
            @Override
            public void run() {
                MyApplication.getApp().loadPluginManager(PluginHelper.getInstance().pluginManagerFile);

                /**
                 * @param context context
                 * @param formId  标识本次请求的来源位置，用于区分入口
                 * @param bundle  参数列表, 建议在参数列表加入自己的验证
                 * @param callback 用于从PluginManager实现中返回View
                 */
                Bundle bundle = new Bundle();//插件 zip，这几个参数也都可以不传，直接在 PluginManager 中硬编码
                bundle.putString(Constant.KEY_PLUGIN_ZIP_PATH, PluginHelper.getInstance().pluginZipFile.getAbsolutePath());
                bundle.putString(Constant.KEY_PLUGIN_NAME, Constant.PLUGIN_APP_COPY_NAME);// partKey 每个插件都有自己的 partKey 用来区分多个插件，如何配置在下面讲到
                bundle.putString(Constant.KEY_ACTIVITY_CLASSNAME, "com.test.plugin_app_copy.SplashActivity");//要启动的插件的Activity页面
                bundle.putBundle(Constant.KEY_EXTRAS, new Bundle()); // 要传入到插件里的参数
                MyApplication.getApp().getPluginManager().enter(MainActivity.this, Constant.FROM_ID_START_ACTIVITY, bundle, new EnterCallback() {
                    @Override
                    public void onShowLoadingView(View view) {
                        loading("VISIBLE");
                        Log.e("PluginLoad", "onShowLoadingView");
                    }

                    @Override
                    public void onCloseLoadingView() {
                        loading("INVISIBLE");
                        Log.e("PluginLoad", "onCloseLoadingView");
                    }

                    @Override
                    public void onEnterComplete() {
                        // 启动成功
                        Log.e("PluginLoad", "onEnterComplete");
                    }
                });
            }
        });
    }


    // 下载Handler
    Handler handler = new Handler(Looper.getMainLooper()) {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            loadingDialog.dismiss();
            Toast.makeText(MainActivity.this, "下载完成，安装中", Toast.LENGTH_SHORT).show();
            // // 测试下载文件是否存在
            // try {
            //     File f = new File("/data/data/com.test.shadow/download/plugin-app-copy-debug.apk");
            //     if (!f.exists()) {
            //         Log.e("file", "不存在" + f.exists());
            //     } else {
            //         Log.e("file", "存在" + f.exists());
            //     }
            // } catch (Exception e) {
            //     Log.e("file", e.toString());
            // }

            // 实现插件apk安装、加载、运行
//            installZip();


            

            // 解压文件夹
            try {
                unzipFile("/data/data/com.test.shadow/files/plugin-debug.zip", "/data/data/com.test.shadow/files/plugin-debug/");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    };

    // 安装插件
//    private void installZip() {
//        String zipHash = md5File(new File("/data/data/com.test.shadow/download/plugin-app-copy-debug.zip"));
//        Log.e("zipHash", zipHash);
//        SamplePluginManager samplePluginManager = new SamplePluginManager(MainActivity.this);
//        samplePluginManager.installZip("/data/data/com.test.shadow/download/plugin-debug.zip", zipHash, true);
//
//    }

    private void loading(String str) {
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                if (str.equals("VISIBLE")) {
                    btn1.setEnabled(false); btn2.setEnabled(false);
                    progressBar.setVisibility(View.VISIBLE); textView.setVisibility(View.VISIBLE);
                } else {
                    btn1.setEnabled(true); btn2.setEnabled(true);
                    progressBar.setVisibility(View.INVISIBLE); textView.setVisibility(View.INVISIBLE);
                }
            }
        });
    }


    /**
     * 解压下载得ZIP文件包
     * @param zipPtath        需要解压得文件
     * @param outputDirectory 解压到那个目录得地址
     * @throws IOException
     */
    public void unzipFile(String zipPtath, String outputDirectory) throws IOException {
        /**
         * 解压assets的zip压缩文件到指定目录
         * @param context上下文对象
         * @param assetName压缩文件名
         * @param outputDirectory输出目录
         * @param isReWrite是否覆盖
         * @throws IOException
         */

        Log.e("TAG", "开始解压的文件： " + zipPtath + "\n" + "解压的目标路径：" + outputDirectory);
        // 创建解压目标目录
        File file = new File(outputDirectory);
        // 如果目标目录不存在，则创建
        if (!file.exists()) {
            file.mkdirs();
        }
        // 打开压缩文件
        InputStream inputStream = new FileInputStream(zipPtath);

        ZipInputStream zipInputStream = new ZipInputStream(inputStream);

        // 读取一个进入点
        ZipEntry zipEntry = zipInputStream.getNextEntry();
        // 使用1Mbuffer
        byte[] buffer = new byte[1024 * 1024];
        // 解压时字节计数
        int count = 0;
        // 如果进入点为空说明已经遍历完所有压缩包中文件和目录
        while (zipEntry != null) {
            Log.e("TAG", "解压文件 入口 1： " + zipEntry);
            if (!zipEntry.isDirectory()) {  //如果是一个文件
                // 如果是文件
                String fileName = zipEntry.getName();
                Log.e("TAG", "解压文件 原来 文件的位置： " + fileName);
                fileName = fileName.substring(fileName.lastIndexOf("/") + 1);  //截取文件的名字 去掉原文件夹名字
                Log.e("TAG", "解压文件 的名字： " + fileName);
                file = new File(outputDirectory + File.separator + fileName);  //放到新的解压的文件路径

                file.createNewFile();
                FileOutputStream fileOutputStream = new FileOutputStream(file);
                while ((count = zipInputStream.read(buffer)) > 0) {
                    fileOutputStream.write(buffer, 0, count);
                }
                fileOutputStream.close();

            }

            // 定位到下一个文件入口
            zipEntry = zipInputStream.getNextEntry();
            Log.e("TAG", "解压文件 入口 2： " + zipEntry);
        }
        zipInputStream.close();
        Log.e("TAG", "解压完成");
        File deleteFile = new File("/data/data/com.test.shadow/files/plugin-debug.zip");
        if (deleteFile.exists() && deleteFile.isFile()) {
            if (deleteFile.delete()) {
                Log.e("deleteFile", "Copy_Delete.deleteSingleFile: 删除单个文件成功！");
            } else {
                Log.e("deleteFile", "删除单个文件失败！");
            }
        } else {
            Log.e("deleteFile", "删除单个文件失败：不存在！");
        }
        String zipHash = md5File(new File("/data/data/com.test.shadow/download/plugin-app-copy-debug.apk"));
        Log.e("zipHash", zipHash);
        move("/data/data/com.test.shadow/download/plugin-app-copy-debug.apk", "/data/data/com.test.shadow/files/plugin-debug/");
    }
    
    /**
     * 压缩文件和文件夹
     *
     * @param srcFileString 要压缩的文件或文件夹
     * @param zipFileString 压缩完成的Zip路径
     * @throws Exception
     */
    public void zipFolder(String srcFileString, String zipFileString) throws Exception {
        //创建ZIP
        ZipOutputStream outZip = new ZipOutputStream(new FileOutputStream(zipFileString));
        //创建文件
        File file = new File(srcFileString);
        //压缩
        Log.e("file", "---->"+file.getParent()+"==="+file.getAbsolutePath());
        ZipFiles(file.getParent()+ File.separator, file.getName(), outZip);
        //完成和关闭
        outZip.finish();
        outZip.close();
        // 删除以前文件
        deleteDirectory("/data/data/com.test.shadow/files/plugin-debug");
        btn3.setEnabled(true);
        btn4.setEnabled(true);
        // deleteSingleFile("/data/user/0/com.test.shadow/files/plugin-debug.zip");
        FileUtils.copyDirectory(new File("/data/data/com.test.shadow/files/plugin-debug.zip"), new File("/data/user/0/com.test.shadow/files"));
    }

    /**
     * 压缩文件
     *
     * @param folderString
     * @param fileString
     * @param zipOutputSteam
     * @throws Exception
     */
    private void ZipFiles(String folderString, String fileString, ZipOutputStream zipOutputSteam) throws Exception {
        Log.e("file", "folderString:" + folderString + "\n" +
                "fileString:" + fileString + "\n==========================");
        if (zipOutputSteam == null)
            return;
        File file = new File(folderString + fileString);
        if (file.isFile()) {
            ZipEntry zipEntry = new ZipEntry(fileString);
            FileInputStream inputStream = new FileInputStream(file);
            zipOutputSteam.putNextEntry(zipEntry);
            int len;
            byte[] buffer = new byte[4096];
            while ((len = inputStream.read(buffer)) != -1) {
                zipOutputSteam.write(buffer, 0, len);
            }
            zipOutputSteam.closeEntry();
        } else {
            //文件夹
            String fileList[] = file.list();
            //没有子文件和压缩
            if (fileList.length <= 0) {
                ZipEntry zipEntry = new ZipEntry(fileString + File.separator);
                zipOutputSteam.putNextEntry(zipEntry);
                zipOutputSteam.closeEntry();
            }
            //子文件和递归
            for (int i = 0; i < fileList.length; i++) {
                ZipFiles(folderString+fileString+"/", fileList[i], zipOutputSteam);
            }
        }
    }

    /**
     * 删除文件夹以及目录下的文件
     * @param   filePath 被删除目录的文件路径
     * @return  目录删除成功返回true，否则返回false
     */
    public boolean deleteDirectory(String filePath) {
        boolean flag = false;
        //如果filePath不以文件分隔符结尾，自动添加文件分隔符
        if (!filePath.endsWith(File.separator)) {
            filePath = filePath + File.separator;
        }
        File dirFile = new File(filePath);
        if (!dirFile.exists() || !dirFile.isDirectory()) {
            return false;
        }
        flag = true;
        File[] files = dirFile.listFiles();
        //遍历删除文件夹下的所有文件(包括子目录)
        for (int i = 0; i < files.length; i++) {
            if (files[i].isFile()) {
            //删除子文件
                flag = deleteSingleFile(files[i].getAbsolutePath());
                if (!flag) break;
            } else {
            //删除子目录
                flag = deleteDirectory(files[i].getAbsolutePath());
                if (!flag) break;
            }
        }
        if (!flag) return false;
        //删除当前空目录
        return dirFile.delete();
    };

    public boolean deleteSingleFile(String filePath) {
        File file = new File(filePath);
        if (file.isFile() && file.exists()) {
            return file.delete();
        }
        return false;
    }

    /**
     * 将一个文件移动到另一个文件夹
     * @param oldPath
     * @param newPath
     */
    public void move(String oldPath, String newPath){

        File oldFile = new File(oldPath);//用旧的路径实例化一个file对象
        File fnewpath = new File(newPath);
        if (!fnewpath.exists())
            fnewpath.mkdirs();

        File fnew = new File(newPath + "/" +oldFile.getName());
        if(fnew.exists()) return;
        if(!oldFile.getName().endsWith(".bap")){
            try {
                FileUtils.copyFileToDirectory(oldFile, fnew);
            } catch (IOException e) {
                e.printStackTrace();
            }
            // oldFile.renameTo(fnew); // 移动至
            try {
                zipFolder("/data/data/com.test.shadow/files/plugin-debug", "/data/data/com.test.shadow/files/plugin-debug.zip");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public void testFiles(View view) {
        // 测试压缩后的apk是否存在
        try {
            File f = new File("/data/data/com.test.shadow/files/plugin-debug.zip");
            if(!f.exists()) {
                Log.e("file", "不存在" + f.exists());
            } else {
                Log.e("file", "存在" + f.exists());
            }
        }
        catch (Exception e) {
            Log.e("file", e.toString());
        }
    }

}
